package apiserver

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"git.hortorgames.com/orange/tang/utils"
	"io/ioutil"
	"net/http"
	"net/url"
	"sort"
	"strings"
	"sync"
)

type HortorApiClient struct {
	urlRoot  string
	httpPool *sync.Pool
}

type HortorResponse struct {
	Code  int         `json:"errCode,omitempty"`
	Error string      `json:"errMsg,omitempty"`
	Data  interface{} `json:"data,omitempty"`
}

func NewHortorApiClient(urlRoot string) *HortorApiClient {
	if urlRoot == "" {
		return nil
	}
	return &HortorApiClient{
		urlRoot: urlRoot,
		httpPool: &sync.Pool{
			New: func() interface{} {
				return &http.Client{}
			},
		},
	}
}

func (c *HortorApiClient) PostForm(api string, req map[string]string, resp interface{}) *HortorResponse {
	client := c.httpPool.Get().(*http.Client)
	defer c.httpPool.Put(client)
	form := url.Values{}
	for k, v := range req {
		form.Set(k, v)
	}
	r, err := client.PostForm(c.urlRoot+api, form)
	if err != nil {
		return &HortorResponse{Code: -1, Error: err.Error()}
	}
	if r.StatusCode != 200 {
		return &HortorResponse{Code: -1, Error: r.Status}
	}
	defer r.Body.Close()
	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return &HortorResponse{Code: -1, Error: err.Error()}
	}
	respWrap := &HortorResponse{
		Data: resp,
	}
	err = json.Unmarshal(data, respWrap)
	if err != nil {
		return &HortorResponse{Code: -1, Error: err.Error()}
	}
	return respWrap
}

func (c *HortorApiClient) PostJsonWithSign(api string, req map[string]interface{}, resp interface{}) *HortorResponse {
	client := c.httpPool.Get().(*http.Client)
	defer c.httpPool.Put(client)

	keys := []string{"type", "userIds", "gameId", "taskName", "secret"}
	sort.Slice(keys, func(i, j int) bool {
		return strings.Compare(keys[i], keys[j]) < 0
	})
	sb := bytes.NewBufferString("")
	for _, k := range keys {
		sb.WriteString(k + "=" + fmt.Sprintf("%v", req[k]))
	}
	sum := md5.Sum(sb.Bytes())
	sign := hex.EncodeToString(sum[:])
	delete(req, "secret")
	req["sign"] = sign

	r, err := client.Post(c.urlRoot+api, "application/json; charset=utf-8", bytes.NewReader(utils.JsonEncodeMust(req)))
	if err != nil {
		return &HortorResponse{Code: -1, Error: err.Error()}
	}
	if r.StatusCode != 200 {
		return &HortorResponse{Code: -1, Error: r.Status}
	}
	defer r.Body.Close()
	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return &HortorResponse{Code: -1, Error: err.Error()}
	}
	type Resp struct {
		Code         int    `json:"code,omitempty"`
		Msg          string `json:"msg,omitempty"`
		SuccessCount int    `json:"successCount,omitempty"`
	}
	var resp2 *Resp
	err = json.Unmarshal(data, &resp2)
	if err != nil {
		return &HortorResponse{Code: -1, Error: err.Error()}
	}
	err = json.Unmarshal(data, &resp)
	if err != nil {
		return &HortorResponse{Code: -1, Error: err.Error()}
	}
	return &HortorResponse{Code: resp2.Code, Error: resp2.Msg, Data: resp}
}
